package com.timedomain.him.remake.utils;

import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;

import com.github.heqiao2010.lunar.LunarCalendar;
import com.timedomain.him.remake.Program;
import com.timedomain.him.remake.core.ChannelCreator;
import com.timedomain.him.remake.core.SimplePlayer;
import com.timedomain.him.remake.models.ChatMessage;
import com.timedomain.him.remake.models.CompanionPhoneCall;
import com.timedomain.him.remake.receiver.SpecialEventReceiver;
import com.timedomain.him.remake.ui.MessageActivity;
import com.timedomain.him.remake.yggdrasil.TheWorldTree;
import com.timedomain.him.remake.yggdrasil.YieldChatMessage;
import com.timedomain.him.remake.yggdrasil.YieldSelection;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;


public class SpecialEventManager {

    public static final String EXTRA_TYPE = "type";
    public static final String EXTRA_DATA = "extraData";
    public static final String EXTRA_TIME = "extraTime";

    public static final String BROADCAST_NEW_MESSAGE = "com.timedomain.him.remake.utils.SpecialEventManager.BROADCAST_NEW_MESSAGE";

    private static final int CODE_SPECIAL_EVENT_ALARM = 149;


    public static void checkHasSpecialEvent(Context ctx) {
        if (AppSettings.firstRun) {
            Intent messageIntent = new Intent(ctx, SpecialEventReceiver.class);
            ScheduledEventUtils.scheduleAlarmClock(ctx, CODE_SPECIAL_EVENT_ALARM, messageIntent, -1);
            return;
        }
        HLog.d("World Flags",String.join(", ",TheWorldTree.getAllWorldFlags()));
        if (AppSettings.lastSpecialEventTime == -1) {
            AppSettings.lastSpecialEventTime = TimeUtils.getTimeStampIgnoreTimeZone();
            AppSettings.saveSettings(ctx);
        }
        //                                                                                                                 👇 兼容手动修改时间的做法，迟来的祝福。
        if (TimeUtils.getTimeStampIgnoreTimeZone() - AppSettings.lastSpecialEventTime > 86400000 || TimeUtils.getTimeStampIgnoreTimeZone() < AppSettings.lastSpecialEventTime) {
            AppSettings.lastSpecialEventTime = TimeUtils.dateStampToTimeStamp(TimeUtils.toDateStamp(TimeUtils.getTimeStampIgnoreTimeZone())) + 1;
            AppSettings.saveSettings(ctx);
        }
        while (true) {
            TriggingEventItem specialEventItem = hasNextItem(ctx, AppSettings.lastSpecialEventTime);
            if (specialEventItem != null) {
                if (specialEventItem.triggerTime < TimeUtils.getTimeStampIgnoreTimeZone()) {
                    processOneSpecialEvent(ctx, specialEventItem.item.type, specialEventItem.item.extra,specialEventItem.triggerTime);
                    AppSettings.lastSpecialEventTime = specialEventItem.triggerTime + 1;
                } else {

                    Intent messageIntent = new Intent(ctx, SpecialEventReceiver.class);
                    messageIntent.putExtra(EXTRA_TYPE, specialEventItem.item.type);
                    messageIntent.putExtra(EXTRA_DATA, specialEventItem.item.extra);
                    messageIntent.putExtra(EXTRA_TIME, specialEventItem.triggerTime);
                    ScheduledEventUtils.scheduleAlarmClock(ctx, CODE_SPECIAL_EVENT_ALARM, messageIntent, specialEventItem.triggerTime);
                    return;
                }
            } else {
                return;
            }
        }


    }


    private static TriggingEventItem hasNextItem(Context ctx, long currentTime) {


        List<SpecialEventItem> specialEvents = loadSpecialEventList(ctx);
        SimpleDateFormat sdf = new SimpleDateFormat("MMdd");

        long today = TimeUtils.toSystemTimeStamp(TimeUtils.dateStampToTimeStamp(TimeUtils.toDateStamp(currentTime)));
        long tomorrow = TimeUtils.toSystemTimeStamp(TimeUtils.dateStampToTimeStamp(1L + TimeUtils.toDateStamp(currentTime)));


        String solarDateTip = sdf.format(new Date(today)) + "S";
        String lunarDateTip = getLunarDateTip(today);
        String weekTip = TimeUtils.getDayOfWeek(currentTime)+"W";
        String currentDayTip = "0D";

        HLog.d("today is solar", solarDateTip);
        HLog.d("today is ", lunarDateTip);
        HLog.d("today is ", weekTip);

        for (SpecialEventItem item : specialEvents) {
            if (item.dateTip.equals(solarDateTip) || item.dateTip.equals(lunarDateTip) || item.dateTip.equals(weekTip) || item.dateTip.equals(currentDayTip)) {
                long time = TimeUtils.toEpochedTimeStamp(today) + item.timeOfDay;
                if (currentTime < time) {
                    return new TriggingEventItem(item, time);
                }
            }
        }
        solarDateTip = sdf.format(new Date(tomorrow)) + "S";
        lunarDateTip = getLunarDateTip(tomorrow);
        weekTip = TimeUtils.getDayOfWeek(TimeUtils.toEpochedTimeStamp(tomorrow))+"W";
        currentDayTip = "0D";

        HLog.d("tomorrow is solar", solarDateTip);
        HLog.d("tomorrow is ", lunarDateTip);
        HLog.d("tomorrow is ", weekTip);
        for (SpecialEventItem item : specialEvents) {
            if (item.dateTip.equals(solarDateTip) || item.dateTip.equals(lunarDateTip) || item.dateTip.equals(weekTip) || item.dateTip.equals(currentDayTip)) {
                long time = TimeUtils.toEpochedTimeStamp(tomorrow) + item.timeOfDay;
                if (currentTime < time) {
                    return new TriggingEventItem(item, time);
                }
            }
        }

        return null;
    }

    private static String getLunarDateTip(long systemDateStamp) {
        Calendar solarCalendar = Calendar.getInstance();
        solarCalendar.setTimeInMillis(systemDateStamp);
        LunarCalendar lunarCalendar = LunarCalendar.solar2Lunar(solarCalendar);

        int lmonth = lunarCalendar.getLmonth();
        int lday = lunarCalendar.getLdate();
        boolean isLeapMonth = lunarCalendar.isLeapMonth();
        String str = "";
        if (lmonth < 10) {
            str += "0";
        }
        str += lmonth;
        if (lday < 10) {
            str += "0";
        }
        str += lday;
        if (isLeapMonth) {
            str += "M";
        }
        return str + "L";
    }


    private static List<SpecialEventItem> cachedSpecialEvent = null;

    private static DataPackManager.OnDataPackReloadListener dataPackReloadListener = null;

    private static List<SpecialEventItem> loadSpecialEventList(final Context ctx) {
        if (dataPackReloadListener == null) {
            dataPackReloadListener = ctx1 -> {
                cachedSpecialEvent = null;
                if (!AppSettings.firstRun) {
                    SpecialEventManager.checkHasSpecialEvent(ctx1);
                }
            };
            DataPackManager.registerOnDatapackLoad(dataPackReloadListener);

        }
        if (cachedSpecialEvent != null) {
            return cachedSpecialEvent;
        }
        final List<SpecialEventItem> items = new ArrayList<>();
        Thread t = new Thread(() -> {
            var files = FileUtils.listFiles("chat/event");
            // Collections.sort(files,String::compareToIgnoreCase);
            for (String listFile : files) {
                loadOneSpecialEventFile(ctx,listFile,items);
            }

            Collections.sort(items, (o1, o2) -> o1.timeOfDay - o2.timeOfDay);

        });
        t.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        cachedSpecialEvent = items;
        return items;
    }

    private static void loadOneSpecialEventFile(Context ctx, String filePath, List<SpecialEventItem> items) {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(Program.openAsset(ctx, filePath)))) {
            String line = null;
            while ((line = br.readLine()) != null) {
                line = line.trim();
                if (TextUtils.isEmpty(line)) {
                    continue;
                }
                if (line.startsWith("#")) {
                    continue;
                }
                String[] params = line.split(Pattern.quote(","));
                if (params.length == 5) {
                    final Iterator<SpecialEventItem> each = items.iterator();
                    while (each.hasNext()) {
                        if (each.next().title.equals(params[1])) {
                            each.remove();
                        }
                    }
                    try {
                        items.add(new SpecialEventItem(params[0], params[1], params[2], params[3], params[4]));
                    } catch (IllegalArgumentException ex2) {
                        ex2.printStackTrace();
                        HLog.e("Failed to parse special event line: ", line);
                    }
                } else {
                    HLog.w("Invalid special event line: ", line);
                }
            }

        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

    public static void processOnMessageReceive(Context context, Intent intent) {
        String type = intent.getStringExtra(EXTRA_TYPE);
        String extra = intent.getStringExtra(EXTRA_DATA);
        long expectedTime = intent.getLongExtra(EXTRA_TIME,TimeUtils.getTimeStampIgnoreTimeZone());
        processOneSpecialEvent(context, type, extra,expectedTime);
        AppSettings.lastSpecialEventTime = TimeUtils.getTimeStampIgnoreTimeZone();
        AppSettings.saveSettings(context);
        SpecialEventManager.checkHasSpecialEvent(context);
    }

    private static void processOneSpecialEvent(Context context, String type, String extra,long time) {

        switch (type) {
            case SpecialEventItem.TYPE_CHAT:
                nextStep(context,extra,time);
                break;

            case SpecialEventItem.TYPE_FLAG:
            {
                String[] strs = extra.split(Pattern.quote(":"));
                String flag = strs[0];
                double hours = Double.parseDouble(strs[1].replace("h",""));
                long expire = time + (long)(hours * 60 * 60 * 1000);
                TheWorldTree.TimedFlags tf = new TheWorldTree.TimedFlags(flag,expire);
                AppSettings.timedFlags.add(tf.toString());
                AppSettings.saveSettings(context);
            }
                break;
            default:
                HLog.e("Unknown special event type: ", type);

        }
    }

    private static void nextStep(Context ctx,String intialState,long time){
        TheWorldTree theWorldTree = new TheWorldTree(ctx);
        theWorldTree.loadState(intialState);
        String message = "点击查看";
        try {
            theWorldTree.nextTick();
        } catch (YieldChatMessage yieldChatMessage) {
            ChatMessage cm = new ChatMessage(time,"",ChatMessage.TYPE_TIME,"","");
            DB.ChatMessage.Add(cm);
            yieldChatMessage.message.date = time+1;
            DB.ChatMessage.Add(yieldChatMessage.message);
            message = "「他」: "+yieldChatMessage.message.toGeneralString();
            if(cm.type == ChatMessage.TYPE_PHONE_CALL){
                String duration = "--";
                try(SimplePlayer sp = new SimplePlayer(ChannelCreator.FromFile(ctx,cm.audioFile))){
                    duration = TimeUtils.msToTimeStr(sp.getDuration());
                }
                CompanionPhoneCall call = new CompanionPhoneCall(
                        FileUtils.getFileNameWithoutExtension(cm.audioFile),
                        cm.audioFile,
                        TimeUtils.getTimeStampIgnoreTimeZone(),
                        duration
                );
                DB.CompanionPhoneCall.Add(call);
            }
        } catch (YieldSelection yieldSelection) {
            // Do nothing
        }
        AppSettings.savedWorldState = theWorldTree.saveState();
        AppSettings.lastChatMessageTime = time;
        AppSettings.saveSettings(ctx);
        NotificationUtils.postNoificationAllowRemoval(ctx,"「他」(1条新消息)",message, MessageActivity.class);
        ctx.sendBroadcast(new Intent(BROADCAST_NEW_MESSAGE));

    }

    public static class SpecialEventItem {
        public String type;
        public String title;
        public String dateTip;
        public int timeOfDay;
        public String extra;

        public static final String TYPE_CHAT = "Chat";
        public static final String TYPE_FLAG = "Flag";

        public SpecialEventItem(String type, String title, String dateTip, String timeOfDay, String extra) {
            this.type = type;
            this.title = title;
            this.dateTip = dateTip;
            this.extra = extra;
            int hour = Integer.parseInt(timeOfDay.substring(0, 2)) - 4;
            int minute = Integer.parseInt(timeOfDay.substring(2));
            this.timeOfDay = hour * 3600000 + minute * 60000;
        }
    }

    public static class TriggingEventItem {
        public long triggerTime;
        SpecialEventItem item;

        public TriggingEventItem(SpecialEventItem item, long time) {
            this.triggerTime = time;
            this.item = item;
        }
    }
}




